export const isObject = (value) => Object.prototype.toString.call(value) === '[object Object]'
export const isNull = (value) => value === null || value === 'null'
export const isUndefined = (value) => value === undefined || value === 'undefined'

class EventController {
    caches = new Set()
    /**
     * 绑定事件
     * @doc https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget/addEventListener
     * @param {Element} el 
     * @param {string} eventName 
     * @param {Function} eventHandler 
     * @param {Object} options 
     */
    bind(el, eventName, eventHandler, options) {
        if (!el || !eventName || !eventHandler) {
            return
        }
        if (!el._eventHandler) {
            el._eventHandler = true
            this.caches.add([el, eventName, eventHandler, options])
            el.addEventListener(eventName, eventHandler, options)
        }
    }
    unbind() {
        this.caches.forEach((value) => {
            const [el, eventName, eventHandler, options] = value
            el.removeEventListener(eventName, eventHandler, options)
        })
        this.caches.clear()
    }
}

export class BaseElement extends HTMLElement {
    constructor() {
        super()
        const shadowRoot = this.attachShadow({ mode: "open" })
        shadowRoot.innerHTML = `<style>${this.getCSSStyle()}</style>
            ${this.render()}`
    }
    // 定义属性
    props = {
        /* example */
        // type: {
        //     type: 'string',
        //     default: ''
        //     observe: true | false
        // }
        // open: {
        //     type: 'boolean',
        //     default: null
        // }
    }
    // 设置属性的值
    setProperty(name, originValue) {
        if (!name) {
            return
        }
        const propMap = this.props?.[name]
        if (!propMap) {
            this.setAttribute(name, originValue)
            return
        }
        switch (propMap.type) {
            case 'boolean': {
                if (originValue) {
                    this.setAttribute(name, '')
                } else {
                    this.removeAttribute(name)
                }
                break
            }
            // string
            default: {
                this.setAttribute(name, originValue ?? '')
                break
            }
        }
    }
    // 获取属性的值
    getProperty(name) {
        if (!name) {
            return
        }
        // 如果为 ''，默认表示为 true
        // 没有该属性时，值为 null，则定义为 false
        const originValue = this.getAttribute(name)
        if (!isObject(this.defineProps)) {
            return originValue
        }
        const propMap = this.props?.[name]
        if (!propMap) {
            return originValue
        }
        const {
            type,
            default: propDefault
        } = propMap
        switch (type) {
            case 'boolean': {
                return isNull(originValue)
                    ? false
                    : val === '' || val === 'true'
            }
            // string
            default: {
                return originValue || typeof propDefault === 'function'
                    ? propDefault()
                    : (propDefault ?? '')
            }
        }
    }
    // 返回css字符串
    getCSSStyle() {
        return ''
    }
    // 返回html字符串
    render() {
        return ''
    }
    // 生命周期，挂载后回调，不可改
    connectedCallback() {
        if (typeof this.mounted === 'function') {
            this.mounted()
        }
        // console.log('connectedCallback')
    }
    // 属性更新后回调，不可改
    attributeChangedCallback(name, oldValue, newValue) {
        if (typeof this.updated === 'function') {
            this.updated(name, oldValue, newValue)
        }
        // console.log('attributeChangedCallback')
    }
    // 生命周期，卸载载后回调，不可改
    disconnectedCallback() {
        if (typeof this.unmounted === 'function') {
            this.unmounted()
        }
        this.#event.unbind()
        // console.log('disconnectedCallback')
    }
    // 实现挂载后的处理
    mounted() { }
    // 实现属性更新后的处理
    updated() { }
    // 实现卸载后的处理
    unmounted() { }
    #event = new EventController()
    // 绑定事件快捷函数
    $on(el, eventName, eventHandler, options) {
        this.#event.bind(el, eventName, eventHandler, options)
    }
    /**
     * 提交发布事件给外部
     * https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget/dispatchEvent
     * @param {String} eventName 
     * @param {Object} customEventInit 
     * @returns 
     */
    $emit(eventName, customEventInit) {
        return this.dispatchEvent(new CustomEvent(eventName, customEventInit))
    }
    // 单个选择器
    $qs(selector) {
        return this.shadowRoot.querySelector(selector)
    }
    // 多个选择器
    $qsa(selector) {
        return this.shadowRoot.querySelectorAll(selector)
    }
}
